/**
 * InvientEngine - Experimental physics and graphics library
 * Copyright (C) 2011  Shane Transue
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/gpl.html
 *
 * No line in this file should exceed 80 characters in width.
 */

package com.invient.math;

/**
 * The Matrix class maintains the data array that is used for all specific
 * Matrix implementations. This representation does not limit the creation of 
 * any specific Matrix. The Matrices that use this abstract class must maintain
 * their own indexing schemes.
 *
 * The performance of many components may be closely related to the performance
 * of the Matrix class it uses. The design of this class and the Matrix 
 * classes that implement it is directed towards performance. This means that 
 * this class holds a primitive float array to allow for the fastest retrieval 
 * of internal data.
 */
public abstract class Matrixf
{
    protected static final float IDENTITY_VALUE = 1.0f;
    protected float[] data;
    
    /**
     * This method sets the data maintained by the Matrix to the provided
     * data. The data provided is copied into the data of this Matrix. The
     * size of the input float array must match the MATRIX_SIZE constant.
     * 
     * @param data The new data that will be copied into this Matrix.
     * @throws IllegalArgumentException If the provided array is not the
     * correct length.
     */
    public void setData(float[] data) {
        if ( data == null )
            throw new IllegalArgumentException("[Matrixf] Error cannot set" +
                " the data of a Matrixf to null");
        if ( data.length != this.data.length )
            throw new IllegalArgumentException("[Matrixf] Error input data" + 
                " array could not be applied to Matrixf the length was" +
                " incorrect: " + data.length);
         
        for ( int i = 0; i < this.data.length; i++ )
            this.data[i] = data[i];
    }
    
    /**
     * This method returns the data included in the Matrix.
     *
     * @return Returns the data included in the Matrix.
     */
    public float[] getData() {
        return this.data;
    }
    
    /**
     * The implementation of this method should set the value at the
     * provided indicies in the Matrix. Since the representation of a Matrix
     * is based on a single dimensional array, the index of the desired
     * member must be calculated from the provided row and column indicies i
     * and j. This calculation will depend on the specific implementation
     * of the Matrix. The determination of a Matrix being row or column
     * major is left to the implementations of this abstract class.
     * 
     * @param i The first index of the item to be changed.
     * @param j The second index of the item to be changed.
     * @param data The new data that will be copied into the position defined
     * by the parameters i and j.
     */
    public abstract void set(int i, int j, float data);
    
    /**
     * The implementation of this method should retrieve the value at the
     * provided indicies in the Matrix. Since the representation of a Matrix
     * is based on a single dimensional array, the index of the desired
     * member must be calculated from the provided row and column indicies i
     * and j. This calculation will depend on the specific implementation
     * of the Matrix. The determination of a Matrix being row or column
     * major is left to the implementations of this abstract class.
     *
     * @param i The first index of the item to be returned.
     * @param j The second index of the item to be returned.
     * @return Returns the value specified in the Matrix at the provided
     * indicies.
     */
    public abstract float get(int i, int j);
    
    /** 
     * Loads the identity Matrix into the Matrix. The identity Matrix is defined
     * as:<br /><br />
     *
     * [ 1 0 0 0 ]<br />
     * [ 0 . 0 . ]<br />
     * [ 0 0 . . ]<br />
     * [ 0 . . 1 ]<br /><br />
     *
     * This is the Matrix that will be loaded.
     */
    public void identity(int matrixSize, int matrixRowSize) {
        for ( int i = 0; i < matrixSize; i++ ) {
            if ( i % (matrixRowSize + 1) == 0 )
                this.data[i] = IDENTITY_VALUE;
            else
                this.data[i] = 0.0f;
        }
    }
}